Completed
Push — master ( d0979c...22246f )
by Sander
49s
created

window.PAPI.constructor   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 225

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 225
rs 8.2857
c 0
b 0
f 0

19 Functions

Rating   Name   Duplication   Size   Complexity  
A _API.encryptSharedCredential 0 11 2
A _API.getVaults 0 3 1
A _API.credentialsSet 0 6 1
A _API.encryptString 0 6 1
A _API.getVault 0 3 1
A _API.createCredential 0 6 1
A _API.createCredential 0 13 1
A _API.decryptString 0 10 2
B _API.newCredential 0 24 1
A _API.encryptCredential 0 8 2
A _API.decryptCredential 0 21 4
B api.js ➔ api_request 0 44 2
A api.js ➔ ... ➔ fetch.then 0 21 4
A api.js ➔ ... ➔ response.then 0 8 2
A _API.getCredendialsSharedWithUs 0 3 1
A api.js ➔ ... ➔ fetch.catch 0 4 1
B _API.decryptSharedCredential 0 23 5
C _API.updateCredential 0 31 8
A _API.updateCredential 0 3 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/* global sjcl */
2
3
window.PAPI = (function () {
4
    var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
5
    var encryption_config = {
6
        adata: "",
7
        iter: 1000,
8
        ks: 256,
9
        mode: 'ccm',
10
        ts: 64
11
    };
12
    var _API = {
13
        username: '',
14
        password: '',
15
        host: '',
16
17
        getVaults: function (callback) {
18
            api_request('/api/v2/vaults', 'GET', null, callback);
19
        },
20
        getVault: function (vault_guid, callback) {
21
            api_request('/api/v2/vaults/' + vault_guid, 'GET', null, callback);
22
        },
23
        credentialsSet: function () {
24
            var hostSet = (typeof this.host !== 'undefined');
25
            var usernameSet = (this.username !== 'undefined');
26
            var passwordSet = (typeof this.password !== 'undefined');
27
            return (hostSet && usernameSet && passwordSet);
28
        },
29
        decryptString: function (ciphertext, _key) {
30
            ciphertext = window.atob(ciphertext);
31
            var rp = {};
32
            try {
33
                /** global: sjcl */
34
                return sjcl.decrypt(_key, ciphertext, encryption_config, rp);
35
            } catch (e) {
36
                throw e;
37
            }
38
        },
39
        decryptCredential: function (credential, key) {
40
            for (var i = 0; i < _encryptedFields.length; i++) {
41
                var field = _encryptedFields[i];
42
                var fieldValue = credential[field];
43
                var field_decrypted_value;
44
                try {
45
                    field_decrypted_value = this.decryptString(fieldValue, key);
46
                } catch (e) {
47
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
48
                    //throw e;
49
                }
50
                try {
51
                    credential[field] = JSON.parse(field_decrypted_value);
52
                } catch (e) {
53
                    console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
54
                }
55
56
            }
57
            return credential;
58
59
        },
60
        encryptString: function (string, _key) {
61
            var rp = {};
62
            /** global: sjcl */
63
            var ct = sjcl.encrypt(_key, string, encryption_config, rp);
64
            return window.btoa(ct);
65
        },
66
        newCredential: function () {
67
            return {
68
                'credential_id': null,
69
                'guid': null,
70
                'vault_id': null,
71
                'label': null,
72
                'description': null,
73
                'created': null,
74
                'changed': null,
75
                'tags': [],
76
                'email': null,
77
                'username': null,
78
                'password': null,
79
                'url': null,
80
                'favicon': null,
81
                'renew_interval': null,
82
                'expire_time': 0,
83
                'delete_time': 0,
84
                'files': [],
85
                'custom_fields': [],
86
                'otp': {},
87
                'hidden': false
88
            };
89
        },
90
        encryptCredential: function (credential, _key) {
91
            for (var i = 0; i < _encryptedFields.length; i++) {
92
                var field = _encryptedFields[i];
93
                var fieldValue = credential[field];
94
                credential[field] = this.encryptString(JSON.stringify(fieldValue), _key);
95
            }
96
            return credential;
97
        },
98
        createCredential: function (credential, _key, callback) {
99
            credential = this.encryptCredential(credential, _key);
100
101
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
102
            var _that = this;
103
104
            api_request('/api/v2/credentials', 'POST', credential, function (r) {
105
                credential.credential_id = r.credential_id;
106
                credential.guid = r.guid;
107
                credential = _that.decryptCredential(credential, _key);
108
                callback(credential);
109
            });
110
        },
111
        encryptSharedCredential: function (credential, sharedKey, origKey) {
112
            var _credential = credential;
113
            _credential.shared_key = this.encryptString(sharedKey, origKey);
114
            var encrypted_fields = _encryptedFields;
115
            for (var i = 0; i < encrypted_fields.length; i++) {
116
                var field = encrypted_fields[i];
117
                var fieldValue = credential[field];
118
                _credential[field] = this.encryptString(JSON.stringify(fieldValue), sharedKey);
119
            }
120
            return _credential;
121
        },
122
        getCredendialsSharedWithUs: function (vault_guid, callback) {
123
            api_request('/api/v2/sharing/vault/' + vault_guid + '/get', 'GET', null, callback);
124
        },
125
        decryptSharedCredential: function (credential, sharedKey) {
126
            var encrypted_fields = _encryptedFields;
127
            for (var i = 0; i < encrypted_fields.length; i++) {
128
                var field = encrypted_fields[i];
129
                var fieldValue = credential[field];
130
                var field_decrypted_value;
131
                if (credential.hasOwnProperty(field)) {
132
                    try {
133
                        field_decrypted_value = this.decryptString(fieldValue, sharedKey);
134
                    } catch (e) {
135
                        throw e;
136
                    }
137
                    try {
138
                        credential[field] = JSON.parse(field_decrypted_value);
139
                    } catch (e) {
140
                        console.warn('Field' + field + ' in ' + _credential.label + ' could not be parsed! Value:' + fieldValue);
0 ignored issues
show
Bug introduced by
The variable _credential seems to be never declared. If this is a global, consider adding a /** global: _credential */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
141
                        throw e;
142
                    }
143
                }
144
            }
145
            return credential;
146
            //console.log(this.decryptCredential(credental, decrypted_key));
147
        },
148
        updateCredential: function (credential, key, callback) {
149
            var origKey = key;
150
            var _credential, _key;
151
            if (!credential.hasOwnProperty('acl') && credential.hasOwnProperty('shared_key')) {
152
                if (credential.shared_key) {
153
                    _key = this.decryptString(credential.shared_key);
154
                }
155
            }
156
157
            if (credential.hasOwnProperty('acl')) {
158
                _key = this.decryptString(credential.acl.shared_key);
159
            }
160
161
            if (_key) {
162
                _credential = this.encryptSharedCredential(credential, _key, origKey);
163
            } else {
164
                _credential = credential;
165
            }
166
            delete _credential.shared_key;
167
            var regex = /(<([^>]+)>)/ig;
168
            if(_credential.description && _credential.description !== "") {
169
                _credential.description = _credential.description.replace(regex, "");
170
            }
171
172
173
            credential = this.encryptCredential(_credential, key);
174
            credential.expire_time = new Date(credential.expire_time).getTime() / 1000;
175
            api_request('/api/v2/credentials/' + credential.guid, 'PATCH', credential, function () {
176
                callback(credential);
177
            });
178
        }
179
    };
180
181
    var api_request = function (endpoint, method, data, callback) {
182
        var encodedLogin = btoa(_API.username + ":" + _API.password);
183
184
        var headers = new Headers();
0 ignored issues
show
Bug introduced by
The variable Headers seems to be never declared. If this is a global, consider adding a /** global: Headers */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
185
        headers.append('Authorization', 'Basic ' + encodedLogin);
186
        headers.append("Accept", " application/json, text/plain, */*");
187
        var opts = {
188
            method: method,
189
            headers: headers
190
191
        };
192
193
        if(method.toLowerCase() !== 'get'){
194
            headers.append('content-type','application/json;charset=UTF-8');
195
            opts.body = JSON.stringify(data);
196
        }
197
198
        var request = new Request(_API.host + '/index.php/apps/passman' + endpoint, opts);
0 ignored issues
show
Bug introduced by
The variable Request seems to be never declared. If this is a global, consider adding a /** global: Request */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
199
200
        fetch(request).then(function(response){
201
            if(response.status !== 200){
202
                callback({error: true, result: {statusText: response.statusText, status: response.status}});
203
                return;
204
            }
205
206
            var contentType = response.headers.get("content-type");
207
            if(contentType && contentType.indexOf("application/json") !== -1) {
208
                return response.json().then(function(json) {
209
                    if(json){
210
                        callback(json);
211
                    } else {
212
                        callback({error: true, result: {statusText: 'Empty reply from server', status: 0}});
213
                    }
214
215
                });
216
            } else {
217
                callback({error: true, result: {statusText: 'Invalid reply from server', status: 0}});
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
218
            }
219
220
        }).catch(function (e) {
221
            API.notifications.create('Error', 'Error connecting to server (Error: '+ e +')');
222
            callback({error: true, result: {statusText: e, status: 0}});
223
        });
224
    };
225
226
    return _API;
227
}());